﻿// Allows the component to be manipulated usng the DOM once it is rendered
define([
'Xjs/core/util',
'Xjs/core/dom',
// Ensure the creation of the global Xjs
'Xjs/app'
],
function (util, dom) {
    'use strict';

    var type = 'domManipulator', // Use the type registration to avoid recreating the type
    DomManipulator = Xjs.getType(type);

    if (DomManipulator) { // It has been already loaded
        return DomManipulator;
    }

    // Renders the html from a component
    DomManipulator = util.define({

        initialize: function (conf) {
        },

        type: type, // Set the type

        // The id is required to perform dom manipulations
        assertId: function () {
            if (!this.id) {
                throw 'Id is required to manipulate the DOM. type: ' + this.type;
            }
        },


        setValue: function (val) {
            this.assertId();
            dom.setValue(this.id, val);
        },

        getValue: function () {
            this.assertId();
            return dom.getValue(this.id);
        },

        // Shows the component
        show: function () {

            if (this.hidden === false) {
                console.log('Element: ' + this.id + ' is already shown');
                return;
            }
            this.assertId();
            dom.show(this.id);
            this.hidden = false;
        },

        // Hides the component
        hide: function () {

            if (this.hidden === true) {
                console.log('Element: ' + this.id + ' is already hidden');
                return;
            }

            this.assertId();
            dom.hide(this.id);
            this.hidden = true;
        },

        setVisible: function (visible) {

            if (this.visible == visible) {
                console.log('Element: ' + this.id + ' is already ' + (visible ? 'visible' : 'not visible'));
                return;
            }

            this.assertId();
            dom.setVisible(this.id, visible);
            this.visible = visible;
        },

        // Enables the component
        enable: function () {

            if (this.disabled === false) {
                console.log('Element: ' + this.id + ' is already enabled');
                return;
            }

            this.assertId();
            dom.enable(this.id);
            this.disabled = false;
        },

        // Disables the component
        disable: function () {

            if (this.disabled === true) {
                console.log('Element: ' + this.id + ' is already disabled');
                return;
            }

            this.assertId();
            dom.disable(this.id);
            this.disabled = true;
        },

        // Returns true if the component has the class, otherwise it returns false
        hasClass: function (cls) {
            this.assertId();
            return dom.hasClass(this.id, cls);
        },

        // Adds the class to the component
        addClass: function (cls) {

            if (this.rendered) {
                this.assertId();
                dom.addClass(this.id, cls);
            }
            else {
                this.builder.addClass(cls);
            }
        },

        // Removes the class from the component
        removeClass: function (cls) {
            this.assertId();
            dom.removeClass(this.id, cls);
        },

        // Replaces the class(es) 'p' in the component with the 'n' ones
        replaceClass: function (p, n) {
            if (this.rendered) {
                this.assertId();
                dom.replaceClass(this.id, p, n);
            }
            else {
                this.builder.replaceClass(p, n);
            }
        },

        toggleClass: function (cls) {
            this.assertId();
            dom.toggleClass(this.id, cls);
        },

        // Sets the left position of the element
        setLeft: function (pos, units) {
            this.assertId();
            dom.setLeft(this.id, pos, units);
        },

        // Sets the top position of the element
        setTop: function (pos, units) {
            this.assertId();
            dom.setTop(this.id, pos, units);
        },

        left: function () {
            this.assertId();
            return dom.left(this.id);
        },

        right: function () {
            this.assertId();
            return dom.right(this.id);
        },

        top: function () {
            this.assertId();
            return dom.top(this.id);
        },

        bottom: function () {
            this.assertId();
            return dom.bottom(this.id);
        },

        width: function () {
            this.assertId();
            return dom.width(this.id);
        },

        height: function () {
            this.assertId();
            return dom.height(this.id);
        },

        move: function (x, y, units) {
            this.assertId();
            return dom.move(this.id, x, y, units);
        },

        setAttribute: function (name, value) {
            if (this.rendered) {
                this.assertId();
                dom.setAttribute(this.id, name, value);
            }
            else {
                var attr = {};
                attr[name] = value;

                this.builder.addAttributes(attr);
            }
        },

        // Set the html content of this component
        setContent: function (content) {
            this.setContent(content);

            if (this.rendered) {
                this.assertId();
                dom.setContent(this.id, content);
            }
        },

        // Return the html content of this component
        getContent: function () {
            return this.getContent(); // No need to get it from the DOM since it is in synch when set
        },

        // Adds an event handler
        on: function (evt, callback, scope) {

            scope = scope || this;
            scope.assertId();
            scope.events = scope.events || {}; // Make sure the object with the bound events exist

            dom.on(scope.id, evt, callback);
            scope.events[evt] = callback; // Register the callback to allow to remove it if needed
        },

        // Removes the event identified by evt or if non is provided it removes all
        off: function (evt) {
            this.assertId();
            if (this.events) { // Remove only if there are bound events
                if (evt && this.events[evt]) { // Remove this event only
                    dom.off(this.id, evt, this.events[evt]);
                    delete this.events[evt];
                }
                else { // Remove all the events of the element
                    for (var ev in this.events) {
                        dom.off(this.id, ev, this.events[ev]);
                        delete this.events[ev];
                    }
                }
            }
        },

        // Removes this component from the DOM
        remove: function () {
            this.assertId();
            dom.remove(this.id);
        }
    });

    Xjs.registerType(DomManipulator);

    return DomManipulator;
});
